import baseClass.ErrorParse;
import baseClass.ErrorSema;
import baseClass.ErrorToken;
import errorHandle.ErrorDeliver;
import intermediateCodeClass.MidCode;
import intermediateCodeClass.ParaGenerate;
import log4Compile.Log;
import symbolClass.ParaMap;

import java.io.*;
import java.util.ArrayList;
import java.util.Scanner;

// 执行单元
public class Main {

    private static ANTLR4 antlr4 = ANTLR4.getInstance();
    private static ErrorDeliver errorDeliver = ErrorDeliver.getErrorDeliverInstance();
    private static MidCode midCode = MidCode.getInstance();
    private static ParaMap paraMap = ParaMap.getParaMapInstance();
    private static ArrayList<ErrorToken> errorTokens;
    private static ArrayList<ErrorParse> errorParses;
    private static ArrayList<ErrorSema> errorSema;

    private static boolean tokenOutput = false;
    private static boolean treeOutput = false;
    private static boolean midOutput = false;
    private static boolean errorOutput = false;
    private static boolean cmdRead = false;

    private static int logLevel = 3;
    private static int optimizationLevel = 1;
    private static Log log = Log.getLogInstance();
    private static String originCodeName;
    private static String tokenListString;
    private static String parseString;
    private static String midCodeString;

    public static void main(String[] args) {
        System.out.println("编译程序启动");
        String command = "";
        Scanner scanner = new Scanner(System.in);
        while (true) {
            System.out.println("请输入参数");
            command = scanner.nextLine();
            if (command.equals("quit")) {
                System.exit(0);
            }
            String[] commandArgs = command.split(" ");
            setArgs(commandArgs);
            log.setLogLevel(logLevel);
            try {
                String originCode = input();
                antlr4.initANTLR4(originCode);
                antlr4.execute("program");
                System.out.println("编译结束");
            } catch (Exception e) {
                System.out.println("编译错误");
            }
            tokenListString = antlr4.tokenString();
//            parseString = antlr4.parseString();
            midCodeString = midCode.toString();

            errorTokens = errorDeliver.getTokenErrorList();
            errorParses = errorDeliver.getParseErrorList();
            errorSema = errorDeliver.getSemaErrorList();

            outPut();
            System.out.println("编译结束");
            cleanUp();
        }
    }

    /*
        -L? ->设置日志级别
        -O? ->设置优化级别
        -token ->设置控制台输出token流
        -tree ->设置控制台输出语法树
        -error ->设置控制台输出错误处理
        -cmd ->表示设置用控制台输入代码
        -mid ->设置控制台输出中间代码
        -path ? ->设置文件路径与文件名
     */
    private static boolean setArgs(String[] args) {
        boolean hasCode = false;
        for (int i = 0; i < args.length; i++) {
            String arg = args[i];
            System.out.println(arg);
            String lowerCase = arg.toLowerCase();
            if (lowerCase.startsWith("-o")) {
                int oLevel = Integer.parseInt(lowerCase.substring(2));
                if (oLevel < 3) {
                    optimizationLevel = oLevel;
                } else {
                    System.err.println("优化级别设置错误，请设置0-2的优化级别");
                }
            } else if (lowerCase.startsWith("-l")) {
                int lLevel = Integer.parseInt(lowerCase.substring(2));
                if (lLevel <= 5 && lLevel >= 0) {
                    logLevel = lLevel;
                } else {
                    System.err.println("日志级别设置错误，请设置0-5的日志级别");
                }
            } else if (lowerCase.equals("-token")) {
                tokenOutput = true;
            } else if (lowerCase.equals("-tree")) {
                treeOutput = true;
            } else if (lowerCase.equals("-error")) {
                errorOutput = true;
            } else if (lowerCase.endsWith("-path")) {
                hasCode = true;
                i++;
                if (i > args.length) {
                    System.err.println("命令格式错误，请将文件路径放置在-path参数后");
                }
                System.out.println(args[i]);
                originCodeName = args[i];
            } else if (lowerCase.equals("-cmd")) {
                cmdRead = true;
            } else if (lowerCase.equals("-mid")) {
                midOutput = true;
            }
        }
        return hasCode;
    }

    private static String input() {
        StringBuilder originCode = new StringBuilder();
        if (cmdRead) {
            Scanner codeRead = new Scanner(System.in);
            boolean hasNextLine = codeRead.hasNextLine();
            while (hasNextLine) {
                String nowLine = codeRead.nextLine();
                if (nowLine.toLowerCase().equals("quit"))
                    break;
                originCode.append(nowLine);
                hasNextLine = codeRead.hasNextLine();
            }
            return originCode.toString();
        } else {
//            String rootAddress = "src/main/java/";
            String rootAddress = "";
            String fileAddress = rootAddress + originCodeName;
            try {
                FileReader bufferReader = new FileReader(fileAddress);
                BufferedReader bufferedReader = new BufferedReader(bufferReader);
                String line = bufferedReader.readLine();
                while (line != null) {
                    originCode.append(line);
                    line = bufferedReader.readLine();
                }
                return originCode.toString();
            } catch (FileNotFoundException e) {
                System.out.println("文件未找到");
            } catch (IOException e) {
                System.out.println("文件内容读取错误");
            }
            return null;
        }
    }

    private static void outPut() {

        if (tokenOutput) {
            System.out.println("Token流如下：");
            System.out.println(tokenListString);
        }
        if (treeOutput) {
            System.out.println("");
            System.out.println(parseString);
        }
        if (errorOutput) {
            System.out.println("词法错误如下：");
            for (ErrorToken errorToken : errorTokens) {
                System.out.println(errorToken);
            }
            System.out.println("语法错误如下：");
            for (ErrorParse errorParse : errorParses) {
                System.out.println(errorParse);
            }
            System.out.println("语义错误如下：");
            for (ErrorSema sema : errorSema) {
                System.out.println(sema);
            }
        }
        System.out.println(midOutput);
        if (midOutput) {
            log.logger("控制台输出中间代码", 2);
            System.out.println("中间代码如下：");
            System.out.println(midCodeString);
        } else {
            log.logger("文件输出中间代码", 2);
            new File("midCodeFile.txt");
            midCode.writeToFile("midCodeFile.txt");
        }
    }

    private static void cleanUp() {
        logLevel = 3;
        ParaGenerate paraGenerate = ParaGenerate.getInstance();
        paraGenerate.clean();
        MidCode midCode = MidCode.getInstance();
        midCode.clean();
    }
}
